package xc.com.cms.service.impl;

import com.alibaba.fastjson.JSON;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.client.RestTemplate;
import xc.com.cms.config.RabbitmqConfig;
import xc.com.cms.domain.CmsPage;
import xc.com.cms.domain.CmsTemplate;
import xc.com.cms.feign.CourseFeign;
import xc.com.cms.repositor.CmsConfigRepository;
import xc.com.cms.repositor.CmsPageRepository;
import xc.com.cms.repositor.CmsTemplateRepository;
import xc.com.cms.request.QueryPageRequest;
import xc.com.cms.response.CmsCode;
import xc.com.cms.service.CmsPageService;
import xc.com.common.PageVo;
import xc.com.common.Result;
import xc.com.common.StatusCode;
import xc.com.course.domain.CourseView;
import xc.com.exception.ExceptionCast;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@Service
class CmsPageServiceImpl implements CmsPageService {

    @Autowired
    private CmsPageRepository cmsPageRepository;
    @Autowired
    private CmsConfigRepository cmsConfigRepository;
    @Autowired
    private CmsTemplateRepository cmsTemplateRepository;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private GridFsTemplate gridFsTemplate;
   @Autowired
   private GridFSBucket gridFSBucket;
   @Autowired
   private RabbitTemplate rabbitTemplate;
   @Autowired
   private CourseFeign courseFeign;

    @Override
    public PageVo<CmsPage> findList(Integer page, Integer size, QueryPageRequest queryPageRequest) {
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withMatcher("pageAliase", ExampleMatcher.GenericPropertyMatchers.contains()).withIgnorePaths("_class");
        CmsPage cmsPage = new CmsPage();

        if (StringUtils.isNoneEmpty(queryPageRequest.getSiteId())) {
            cmsPage.setSiteId(queryPageRequest.getSiteId());
        }
        if (StringUtils.isNoneEmpty(queryPageRequest.getTemplateId())) {
            cmsPage.setTemplateId(queryPageRequest.getTemplateId());
        }
        if (StringUtils.isNoneEmpty(queryPageRequest.getPageAliase())) {
            cmsPage.setPageAliase(queryPageRequest.getPageAliase());
        }
        Example<CmsPage> example = Example.of(cmsPage, matcher);

        if (page < 0) {
            page = 1;
        }
        if (size <= 0) {
            size = 10;
        }
        page = page - 1;
        Pageable pageable = PageRequest.of(page, size);
        Page<CmsPage> all = cmsPageRepository.findAll(example, pageable);
        PageVo<CmsPage> cms = new PageVo<>();
        cms.setRows(all.getContent());
        cms.setTotal(all.getTotalElements());
        return cms;
    }

    @Override
    public Result add(CmsPage cmsPage) {
        CmsPage page = cmsPageRepository.
                findByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName(), cmsPage.getSiteId(), cmsPage.getPageWebPath());
        if (page == null) {
            Date date =new Date();
            cmsPage.setPageId(null);
            cmsPage.setPageCreateTime(date);
            cmsPageRepository.save(cmsPage);
            return new Result(true, StatusCode.OK, "添加成功");
        }
        return new Result(false, StatusCode.FAIL, "添加失败，数据库改数据");
    }

    @Override
    public CmsPage getById(String id) {
        Optional<CmsPage> optional = cmsPageRepository.findById(id);
        if (optional.isPresent()) {
            return optional.get();
        }
        return null;
    }

    @Override
    public Result update(String id, CmsPage cmsPage) {
        CmsPage one = this.getById(id);
        if (one != null) {
            CmsPage save = cmsPageRepository.save(cmsPage);
            if (save != null) {
                return new Result(true, StatusCode.OK, "修改成功");
            }
        }
        return new Result(false, StatusCode.FAIL, "修改失败");
    }
    @Override
    public Result delete(String id){
        CmsPage two=this.getById(id);
        if (two!=null){
            cmsPageRepository.deleteById(id);
            return  new Result(true, StatusCode.OK,"删除成功");
        }
        return  new Result(false, StatusCode.FAIL,"删除失败");
    }

    @Override
    public String getPageHtml(String pageId) {
        //获取CmsConfig页面模板数据
        Map model = this.getModelByPageId(pageId);
        //是否为空
        if(model==null){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
        }
        //获取FS页面模板
        String template = this.getTemplateByPageId(pageId);
        //判断是否为空
        if(StringUtils.isEmpty(template)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        //将CmsConfig页面模板数据和FS页面模板集成为静态化
        String html = this.generateHtml(template, model);
        //判断是否为空
        if(StringUtils.isEmpty(html)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_HTMLISNULL);
        }
        return html;
    }
    @Override
    public String generateHtml(String template, Object model) {
        //生成配置类
        Configuration configuration=new Configuration(Configuration.getVersion());
        //模板加载器
        StringTemplateLoader loader = new StringTemplateLoader();
        loader.putTemplate("template",template);
        //配置模板加载器
        configuration.setTemplateLoader(loader);
        try {
            //获取模板
            Template configurationTemplate = configuration.getTemplate("template");
            //集成模板
            String intoString = FreeMarkerTemplateUtils.processTemplateIntoString(configurationTemplate,model);
            return intoString;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    @Override
    public String getTemplateByPageId(String pageId) {
        //查询页面信息
        CmsPage cmsPage = this.getById(pageId);
        //判断是否为空
        if(cmsPage==null){
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        //提取TemplateId
        String pageTemplateId = cmsPage.getTemplateId();
        //判断是否为空
        if(StringUtils.isEmpty(pageTemplateId)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        Optional<CmsTemplate> cmsTemplate = cmsTemplateRepository.findById(pageTemplateId);
        //判断是否为空
        if(cmsTemplate.isPresent()){
            CmsTemplate template = cmsTemplate.get();
            //提取TemplateFileId
            String fileId = template.getTemplateFileId();
            //取出模板内容
            GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(fileId)));
            //打开下载流对象
            GridFSDownloadStream stream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
            //创建GridFsResource
            GridFsResource gridFsResource = new GridFsResource(gridFSFile,stream);
            try {
                return    IOUtils.toString(gridFsResource.getInputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    @Override
    public Map getModelByPageId(String pageId) {
        CmsPage cmsPage = this.getById(pageId);
        if(cmsPage==null){
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        String dataUrl = cmsPage.getDataUrl();
        if(StringUtils.isEmpty(dataUrl)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAURLISNULL);
        }
        ResponseEntity<Map> entity = restTemplate.getForEntity(dataUrl, Map.class);
        Map body = entity.getBody();
        return body;
    }

    @Override
    public Result postPage(String pageId) {
        //获取静态化页面
        String pageHtml = this.getPageHtml(pageId);
        //判断是否为空
        if(StringUtils.isEmpty(pageHtml)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_HTMLISNULL);
        }
        //保存静态页面
        CmsPage cmsPage = this.saveHtml(pageId, pageHtml);
        //发送信息
        sendPostPage(pageId);
        return new Result(true,StatusCode.OK,"发布页面成功");
    }

    /**
     * 课程详情预览
     * @param courseId
     * @return
     */
    @Override
    public String getCourseHtml(String courseId) {
        String tid="60c9e35cf1b932437e6fa473";
        String template = this.getTemplateByPageId(tid);
        CourseView courseView = courseFeign.courseView(courseId);
        //将Course课程信息数据和FS页面模板集成为静态化
        String html = this.getCourseView(template, courseView);
        //判断是否为空
        if(StringUtils.isEmpty(html)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_HTMLISNULL);
        }
        return html;
    }
    public String getCourseView(String template, CourseView model) {
        //生成配置类
        Configuration configuration=new Configuration(Configuration.getVersion());
        //模板加载器
        StringTemplateLoader loader = new StringTemplateLoader();
        loader.putTemplate("template",template);
        //配置模板加载器
        configuration.setTemplateLoader(loader);
        try {
            //获取模板
            Template configurationTemplate = configuration.getTemplate("template");
            //集成模板
            String intoString = FreeMarkerTemplateUtils.processTemplateIntoString(configurationTemplate,model);
            return intoString;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 发送页面发布消息
     * @param pageId
     */
    private void sendPostPage(String pageId){
        //获取页面信息
        CmsPage cmsPage = this.getById(pageId);
        //判断是否为空
        if(cmsPage == null){
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        //创建map集合
         Map<String,String> map=new HashMap<>();
        map.put("pageId",pageId);
        //消息内容
        String string = JSON.toJSONString(map);
        //获取站点id作为routingKey
        String siteId = cmsPage.getSiteId();
        //发布消息
        this.rabbitTemplate.convertAndSend(RabbitmqConfig.EX_ROUTING_CMS_PAGE,siteId,string);

    }

    /**
     * 保存静态页面内容
     * @param pageId
     * @param content
     * @return
     */
    private CmsPage saveHtml(String pageId,String content){
        Optional<CmsPage> repository = cmsPageRepository.findById(pageId);
        if(!repository.isPresent()){
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        //获取页面信息
        CmsPage cmsPage = repository.get();
        String htmlFileId = cmsPage.getHtmlFileId();
        //判断是否为空
        if(StringUtils.isNotEmpty(htmlFileId)){
            //删除id为htmlFileId
            gridFsTemplate.delete(Query.query(Criteria.where("_id").is(htmlFileId)));
        }
        //将静态化页面保存到GridFs中
        InputStream inputStream = IOUtils.toInputStream(content);
        ObjectId objectId = gridFsTemplate.store(inputStream, cmsPage.getPageName());
        //获取文件id
        String id = objectId.toString();
        ////将文件id存储到页面信息中
        cmsPage.setHtmlFileId(id);
        System.out.println(cmsPage);
        this.update(cmsPage.getPageId(),cmsPage);
        return cmsPage;
    }
}

